/*
 * mx01_mx01.c
 *
 * Change Logs:
 * Date           Author            Notes
 * 2023-05-06     qiyongzhong       first version
 */

#include <mx01.h>
#include <rtdevice.h>
#include <stddef.h>
#include <string.h>
#include <rtdef.h> // 解决RT_MIN未定义
#include <rthw.h>  // 提供基础宏定义

#define DBG_TAG "bt.mx01"
#define DBG_LVL DBG_LOG // DBG_INFO  //
#include <rtdbg.h>

#ifndef RT_MIN
#define RT_MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

/* 定义响应超时检测宏 */
#define RESP_TIMEOUT(dev, timeout) \
    (rt_tick_get() - start_tick > rt_tick_from_millisecond(timeout))

struct mx01_device
{
    struct rt_device parent; // 设备数据
    rt_device_t uart_dev;    /*  串口设备句柄 */
    const mx01_cfg_t *cfg;   // 配置参数指针
    struct rt_ringbuffer *rx_rb;
    mx01_status_t status; // 工作状态
};

static rt_err_t uart_rx_callback(rt_device_t dev, rt_size_t size)
{
    mx01_dev_t mx_dev = (mx01_dev_t)rt_container_of(dev, struct mx01_device, parent);
    rt_uint8_t buf[128];
    rt_size_t len = rt_device_read(dev, 0, buf, sizeof(buf));

    if (len > 0)
    {
        rt_ringbuffer_put(mx_dev->rx_rb, buf, len);
        if (mx_dev->parent.rx_indicate)
        {
            mx_dev->parent.rx_indicate(&mx_dev->parent, len);
        }
    }
    return RT_EOK;
}

/* 初始化 UART 设备 */
int mx01_uart_init(mx01_dev_t dev)
{
    /* 配置串口参数 */
    struct serial_configure serial_cfg = RT_SERIAL_CONFIG_DEFAULT;
    serial_cfg.baud_rate = MX01_MX01_BAUDRATE;
    if (rt_device_control(dev->uart_dev, RT_DEVICE_CTRL_CONFIG, &serial_cfg))
    {
        LOG_E("UART config failed");
        return -RT_ERROR;
    }

    /* 打开设备并设置回调 */
    if (rt_device_open(dev->uart_dev, RT_DEVICE_FLAG_INT_RX))
    {
        LOG_E("UART open failed");
        return -RT_ERROR;
    }
    rt_device_set_rx_indicate(dev->uart_dev, uart_rx_callback);
    dev->uart_dev->user_data = dev;
    return RT_EOK;
}

/* 发送 AT 命令并等待响应 */
static int send_at_command(mx01_dev_t dev, const char *cmd,
                           rt_int32_t timeout, const char *expect_resp)
{
    rt_size_t len = rt_device_write(dev->uart_dev, 0, cmd, rt_strlen(cmd));
    if (len != rt_strlen(cmd))
        return -RT_ERROR;

    rt_tick_t start_tick = rt_tick_get();
    char resp_buf[256];
    rt_size_t resp_len = 0;

    while (rt_tick_get() - start_tick < rt_tick_from_millisecond(timeout))
    {
        rt_size_t n = rt_device_read(dev->uart_dev, 0, resp_buf + resp_len, sizeof(resp_buf) - resp_len - 1);
        if (n > 0)
        {
            resp_len += n;
            resp_buf[resp_len] = '\0';
            if (rt_strstr(resp_buf, expect_resp))
                return resp_len;
        }
        rt_thread_mdelay(10);
    }
    return -RT_ETIMEOUT;
}
static int check_disconnect(mx01_dev_t dev)
{
    rt_uint8_t *peek_ptr;
    rt_size_t len = rt_ringbuffer_peek(dev->rx_rb, &peek_ptr); // 修复指针类型

    if (len > 0 && rt_strstr((char *)peek_ptr, "+DISCONN:1"))
    {
        rt_ringbuffer_reset(dev->rx_rb);
        return RT_EOK;
    }
    return -RT_ERROR;
}
static int wait_for_response(mx01_dev_t dev, const char *keyword, rt_int32_t timeout)
{
    rt_tick_t start = rt_tick_get();
    char buf[128];

    while (rt_tick_get() - start < rt_tick_from_millisecond(timeout))
    {
        rt_size_t len = rt_device_read(dev->uart_dev, 0, buf, sizeof(buf) - 1);
        if (len > 0)
        {
            buf[len] = '\0';
            if (rt_strstr(buf, keyword))
            {
                return RT_EOK;
            }
        }
        rt_thread_mdelay(10);
    }
    return -RT_ETIMEOUT;
}
static void mx01_delay_ms(int ms)
{
    if (ms > 0)
    {
        rt_thread_mdelay(ms);
    }
}

static void mx01_pins_init(mx01_dev_t dev)
{
    if (dev->cfg->sleep >= 0)
    {
        rt_pin_mode(dev->cfg->sleep, PIN_MODE_OUTPUT);
        rt_pin_write(dev->cfg->sleep, PIN_HIGH);
    }
}

static void mx01_pins_deinit(mx01_dev_t dev)
{
    if (dev->cfg->sleep >= 0)
    {
        rt_pin_mode(dev->cfg->sleep, PIN_MODE_INPUT);
    }
}

static int mx01_pin_set_sleep(mx01_dev_t dev, int enable)
{
    if (dev->cfg->sleep < 0)
    {
        LOG_E("BT does not support sleep.");
        return (-RT_ERROR);
    }

    rt_pin_write(dev->cfg->sleep, (enable ? PIN_HIGH : PIN_LOW));
    return (RT_EOK);
}

/* 复位命令 */
static int mx01_cmd_reset(mx01_dev_t dev)
{
    return send_at_command(dev, "AT+REBOOT=1\r\n",
                           MX01_MX01_ACK_TMO_MS, "OK") > 0
               ? RT_EOK
               : -RT_ERROR;
}

// 设置蓝牙功率：范围 0-9；重启后生效。
static int mx01_cmd_set_power(mx01_dev_t dev, int power)
{
    char cmd[32];
    rt_snprintf(cmd, sizeof(cmd), "AT+TXPOWER=%d\r\n", power);
    return send_at_command(dev, cmd, MX01_MX01_ACK_TMO_MS, "OK") > 0 ? RT_EOK : -RT_ERROR;
}

// 设置广播间隔：范围 20-10000 ms，重启后生效。
static int mx01_cmd_set_aintvl(mx01_dev_t dev, int aintvl)
{
    char cmd[32];
    rt_snprintf(cmd, sizeof(cmd), "AT+AINTVL=%d\r\n", aintvl);
    return send_at_command(dev, cmd, MX01_MX01_ACK_TMO_MS, "OK") > 0 ? RT_EOK : -RT_ERROR;
}

/* 配置蓝牙名称 */
static int mx01_cmd_set_name(mx01_dev_t dev, const char *name)
{
    char cmd[64];
    rt_snprintf(cmd, sizeof(cmd), "AT+NAME=%s\r\n", name);
    return send_at_command(dev, cmd, MX01_MX01_ACK_TMO_MS, "OK") > 0 ? RT_EOK : -RT_ERROR;
}

/* 查询连接状态 */
static int mx01_cmd_chk_link(mx01_dev_t dev)
{
    if (send_at_command(dev, "AT+DEV?\r\n",
                        MX01_MX01_ACK_TMO_MS, "+DEV:1") > 0)
    {
        return 1; // 已连接
    }
    return 0; // 未连接
}

static int mx01_wait_comm_ok(mx01_dev_t dev) // 等待通信正常
{
    for (int i = 0; i < MX01_MX01_TEST_TIMES; i++)
    {
        mx01_delay_ms(1000);
        if (mx01_cmd_chk_link(dev) >= 0)
        {
            LOG_D("BT communication success.");
            return (RT_EOK);
        }
    }
    LOG_E("BT communication fail.");
    return (-RT_ERROR);
}

static int mx01_reset_chip(mx01_dev_t dev) // 复位芯片
{
    for (int i = 0; i < MX01_MX01_RETRY_TIMES; i++)
    {
        mx01_delay_ms(MX01_MX01_CMD_INTV_MS);
        if (mx01_cmd_reset(dev) == RT_EOK)
        {
            LOG_D("BT reset chip success.");
            return (RT_EOK);
        }
    }
    LOG_E("BT reset chip fail.");
    return (-RT_ERROR);
}

static int mx01_cfg_power(mx01_dev_t dev) // 配置功率
{
    int power = dev->cfg->power;
    for (int i = 0; i < MX01_MX01_RETRY_TIMES; i++)
    {
        mx01_delay_ms(MX01_MX01_CMD_INTV_MS);
        if (mx01_cmd_set_power(dev, power) == RT_EOK)
        {
            LOG_D("BT config power=%d success.", power);
            return (RT_EOK);
        }
    }
    LOG_E("BT config power=%d fail.", power);
    return (-RT_ERROR);
}

static int mx01_cfg_aintvl(mx01_dev_t dev) // 配置广播间隔
{
    int aintvl = dev->cfg->aintvl;
    for (int i = 0; i < MX01_MX01_RETRY_TIMES; i++)
    {
        mx01_delay_ms(MX01_MX01_CMD_INTV_MS);
        if (mx01_cmd_set_aintvl(dev, aintvl) == RT_EOK)
        {
            LOG_D("BT config aintvl=%d success.", aintvl);
            return (RT_EOK);
        }
    }
    LOG_E("BT config aintvl=%d fail.", aintvl);
    return (-RT_ERROR);
}

static int mx01_cfg_name(mx01_dev_t dev) // 配置名字
{
    char name[24];
    strncpy(name, dev->parent.parent.name, RT_NAME_MAX);
    for (int i = 0; i < MX01_MX01_RETRY_TIMES; i++)
    {
        mx01_delay_ms(MX01_MX01_CMD_INTV_MS);
        if (mx01_cmd_set_name(dev, (void *)name) == RT_EOK)
        {
            LOG_D("BT config name success. name = %s", name);
            return (RT_EOK);
        }
    }
    LOG_E("BT config name fail.");
    return (-RT_ERROR);
}

static void mx01_fsm_cfg_deal(mx01_dev_t dev)
{
    if (mx01_wait_comm_ok(dev) != RT_EOK)
    {
        return;
    }
    if (mx01_cfg_power(dev) != RT_EOK)
    {
        return;
    }
    if (mx01_cfg_aintvl(dev) != RT_EOK)
    {
        return;
    }
    if (mx01_reset_chip(dev) != RT_EOK)
    {
        return;
    }
    mx01_delay_ms(1000);
    if (mx01_cfg_name(dev) != RT_EOK)
    {
        return;
    }
    dev->status = MX01_STA_READY;
    LOG_D("BT config ok...");
}

static void mx01_fsm_ready_deal(mx01_dev_t dev)
{
    if (mx01_cmd_chk_link(dev) != 1)
    {
        rt_uint32_t ticks = rt_tick_get();
        while (1)
        {
            char buf[128];
            rt_size_t len = rt_device_read(dev->uart_dev, 0, buf, sizeof(buf));
            if (len > 0 && rt_strstr(buf, "+CONNECTED:1"))
            {
                break;
            }
            if (rt_tick_get() - ticks >= rt_tick_from_millisecond(3 * 1000))
            {
                return;
            }
        }
    }
    dev->status = MX01_STA_CONNECT;
    LOG_D("BT connect...");
}

static void mx01_fsm_connect_deal(mx01_dev_t dev)
{
    if (check_disconnect(dev))
    {
        dev->status = MX01_STA_READY;
        LOG_D("BT disconnected");
    }
}

static void mx01_fsm_sleep_deal(mx01_dev_t dev)
{
    mx01_delay_ms(10);
}

static void mx01_thread_entry(void *args)
{
    mx01_dev_t dev = (mx01_dev_t)args;

    mx01_delay_ms(200);
    while (1)
    {
        switch (dev->status)
        {
        case MX01_STA_CFG:
            mx01_fsm_cfg_deal(dev);
            break;
        case MX01_STA_READY:
            mx01_fsm_ready_deal(dev);
            break;
        case MX01_STA_CONNECT:
            mx01_fsm_connect_deal(dev);
            break;
        case MX01_STA_SLEEP:
            mx01_fsm_sleep_deal(dev);
        default:
            return;
        }
    }
}

static int mx01_thread_create(mx01_dev_t dev)
{
    rt_thread_t tid = rt_thread_create(dev->parent.parent.name, mx01_thread_entry, dev,
                                       MX01_MX01_THREAD_STK_SIZE, MX01_MX01_THREAD_PRIO, 20);
    if (tid == RT_NULL)
    {
        LOG_E("BT create thread fail.");
        return (-RT_ERROR);
    }

    rt_thread_startup(tid);

    LOG_D("BT create thread success.");
    return (RT_EOK);
}

static int mx01_reset(mx01_dev_t dev)
{
    if (dev->status == MX01_STA_CLOSE)
    {
        LOG_E("BT reset fail. it is closed.");
        return (-RT_ERROR);
    }

    mx01_pin_set_sleep(dev, 0);
    dev->status = MX01_STA_CFG;

    LOG_E("BT reset success.");
    return (RT_EOK);
}

static int mx01_sleep(mx01_dev_t dev)
{
    if (dev->status < MX01_STA_READY)
    {
        LOG_E("BT sleep fail. it is not ready.");
        return (-RT_ERROR);
    }

    int rst = mx01_pin_set_sleep(dev, 0);
    if (rst == RT_EOK)
    {
        dev->status = MX01_STA_SLEEP;
    }

    return (rst);
}

static int mx01_wackup(mx01_dev_t dev)
{
    if (dev->status != MX01_STA_SLEEP)
    {
        LOG_D("BT wakeup fail. it is not sleeping.");
        return (RT_EOK);
    }

    int rst = mx01_pin_set_sleep(dev, 0);
    if (rst == RT_EOK)
    {
        LOG_D("BT wakeup success.");
        dev->status = MX01_STA_READY;
    }

    return (rst);
}

static mx01_status_t mx01_get_status(mx01_dev_t dev)
{
    return (dev->status);
}

static int mx01_set_notify(mx01_dev_t dev, rt_err_t (*notify)(rt_device_t dev, rt_size_t size))
{
    return (rt_device_set_rx_indicate((rt_device_t)dev, notify));
}

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops mx01_ops =
    {
        RT_NULL,
        (void *)mx01_open,
        (void *)mx01_close,
        (void *)mx01_read,
        (void *)mx01_write,
        (void *)mx01_control};
#endif

mx01_dev_t mx01_create(const char *name, const mx01_cfg_t *cfg) // 创建蓝牙设备
{
    RT_ASSERT(name != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);
    RT_ASSERT(cfg->serial != RT_NULL);

    rt_device_t device = rt_device_create(RT_Device_Class_Char, (sizeof(struct mx01_device) - sizeof(struct rt_device)));
    if (device == RT_NULL)
    {
        LOG_E("BT create device fail.");
        return (RT_NULL);
    }

    mx01_dev_t dev = (mx01_dev_t)device;
    dev->uart_dev = rt_device_find(cfg->serial);
    if (!dev->uart_dev)
    {
        LOG_E("UART device %s not found!", cfg->serial);
        return (RT_NULL);
    }

    // 配置串口参数
    struct serial_configure serial_cfg = RT_SERIAL_CONFIG_DEFAULT;
    serial_cfg.baud_rate = MX01_MX01_BAUDRATE;
    rt_device_control(dev->uart_dev, RT_DEVICE_CTRL_CONFIG, &serial_cfg);

    // 打开设备（中断接收模式）
    if (rt_device_open(dev->uart_dev, RT_DEVICE_FLAG_INT_RX) != RT_EOK)
    {
        LOG_E("UART device open failed");
        return (RT_NULL);
    }

    dev->rx_rb = rt_ringbuffer_create(cfg->fifo_size);
    if (dev->rx_rb == RT_NULL)
    {
        mx01_destory(dev);
        LOG_E("BT create ringbuffer fail.\n");
        return (RT_NULL);
    }

    dev->cfg = cfg;
    dev->status = MX01_STA_CLOSE;

    mx01_pins_init(dev);

#ifdef RT_USING_DEVICE_OPS
    device->ops = &mx01_ops;
#else
    device->init = RT_NULL;
    device->open = (void *)mx01_open;
    device->close = (void *)mx01_close;
    device->read = (void *)mx01_read;
    device->write = (void *)mx01_write;
    device->control = (void *)mx01_control;
#endif

    rt_device_register((void *)dev, name, RT_DEVICE_FLAG_RDWR);

    LOG_D("BT create device success.\n");

    return (dev);
}

void mx01_destory(mx01_dev_t dev) // 销毁蓝牙设备
{
    RT_ASSERT(dev != RT_NULL);

    mx01_close(dev);
    mx01_pins_deinit(dev);

    if (dev->rx_rb != RT_NULL)
    {
        rt_ringbuffer_destroy(dev->rx_rb);
        dev->rx_rb = RT_NULL;
    }

    if (dev->uart_dev != RT_NULL)
    {
        rt_device_destroy(dev->uart_dev);
        dev->uart_dev = RT_NULL;
    }

    rt_device_destroy((void *)dev);

    LOG_D("BT destory device success.\n");
}

int mx01_open(mx01_dev_t dev) // 打开
{
    RT_ASSERT(dev != RT_NULL);

    if (dev->status != MX01_STA_CLOSE) // 已打开
    {
        LOG_D("BT has been opened.");
        return (RT_EOK);
    }

    rt_thread_t tid = rt_thread_find(dev->parent.parent.name);
    if (tid != RT_NULL)
    {
        LOG_D("BT thread already exists.");
        return (RT_EOK);
    }

    dev->status = MX01_STA_CFG;
    mx01_pin_set_sleep(dev, 0);
    if (mx01_thread_create(dev) != RT_EOK)
    {
        return (-RT_ERROR);
    }

    LOG_D("BT open success.");
    return (RT_EOK);
}

int mx01_close(mx01_dev_t dev) // 关闭
{
    RT_ASSERT(dev != RT_NULL);

    if (dev->status == MX01_STA_CLOSE)
    {
        LOG_D("BT has been closed.");
        return (RT_EOK);
    }

    rt_thread_t tid = rt_thread_find(dev->parent.parent.name);
    if (tid != RT_NULL)
    {
        rt_thread_delete(tid);
    }

    mx01_pin_set_sleep(dev, 1);
    dev->status = MX01_STA_CLOSE;

    LOG_D("BT close success.");
    return (RT_EOK);
}

int mx01_read(mx01_dev_t dev, int pos, void *buf, int bufsize) // 读取接收数据
{
    RT_ASSERT(dev != RT_NULL);
    RT_ASSERT(buf != RT_NULL);
    RT_ASSERT(bufsize > 0);

    if (dev->status != MX01_STA_CONNECT)
    {
        LOG_D("BT read fail. it is not connected.");
        return (-RT_ERROR);
    }
    return (rt_ringbuffer_get(dev->rx_rb, buf, bufsize));
}

/* 数据发送函数 */
int mx01_write(mx01_dev_t dev, int pos, void *buf, int size)
{
    /* 分片发送（避免阻塞） */
    rt_size_t total_sent = 0;
    while (total_sent < size)
    {
        rt_size_t chunk = RT_MIN(size - total_sent, MX01_MX01_MTU);
        rt_size_t sent = rt_device_write(dev->uart_dev, 0,
                                         (char *)buf + total_sent, chunk);
        if (sent != chunk)
        {
            LOG_E("Write failed: %d/%d", sent, chunk);
            return -RT_ERROR;
        }
        total_sent += sent;
        rt_thread_mdelay(MX01_MX01_SEND_INTV_MS);
    }

    /* 触发发送完成回调 */
    if (dev->parent.tx_complete)
    {
        dev->parent.tx_complete(&dev->parent, buf);
    }
    return total_sent;
}

int mx01_control(mx01_dev_t dev, int cmd, void *args) // 控制
{
    RT_ASSERT(dev != RT_NULL);

    int rst = RT_EOK;
    switch (cmd)
    {
    case MX01_CTRL_RESET:
        rst = mx01_reset(dev);
        break;
    case MX01_CTRL_SLEEP:
        rst = mx01_sleep(dev);
        break;
    case MX01_CTRL_WAKEUP:
        rst = mx01_wackup(dev);
        break;
    case MX01_CTRL_GET_STATUS:
        *((mx01_status_t *)args) = mx01_get_status(dev);
        break;
    case MX01_CTRL_SET_NOTIFY:
        rst = mx01_set_notify(dev, args);
        break;
    case MX01_CTRL_CLR_RECV:
        rt_ringbuffer_reset((struct rt_ringbuffer *)(dev->rx_rb));
        break;
    default:
        rst = -RT_ERROR;
        LOG_E("command (%d) does not support", cmd);
        break;
    }

    return (rst);
}
